#include <iostream>
#include <cmath>
#include "histogram.h"

#define ERROR 100000.0

Histogram::Histogram(){
    p = new double[256];
    max = 1.0/255.0;
    min = 0;

    mean = 0;
    variance = 0;

    for(int i = 0; i < 256; i++){
        p[i] = 1.0/255.0;
    }

    setMean();
    setVariance();
}

Histogram::Histogram(Data *_data){
    p = new double[256];
    max = 0;
    min = 2;

    mean = 0;
    variance = 0;

    //assume-se que a imagem eh em preto e branco
    calculate(_data);
    setMean();
    setVariance();
    setMinMax();
}

Histogram::Histogram(double *_p) : p(_p){
    max = 0;
    min = 2;
    mean = 0;
    variance = 0;

    setMean();
    setVariance();
    setMinMax();
}

Histogram::~Histogram(){
    delete[] p;
}

void Histogram::setMinMax(){
    for(int i = 0; i < 256; i++){
        if(p[i] > max) max = p[i];
        else if(p[i] < min) min = p[i];
    }

    if(min == max){
        min = 0;
        max = 1;
    }
}

double Histogram::getP(int _i){
    return p[_i];
}

double Histogram::getNormalizedP(int _i){
    int x0 = min*ERROR;
    int xn = max*ERROR;
    int y0 = 0;
    int yn = 150;

    return normalize(x0, xn, y0, yn, p[_i]*ERROR);
}

double Histogram::getMean(){
    return mean;
}

void Histogram::setMean(){
    for(int i = 0; i < 256; i++){
        mean += i * p[i];
    }
}

double Histogram::getVariance(){
    return variance;
}

void Histogram::setVariance(){
    for(int i = 0; i < 256; i++){
        variance += ((i - mean)*(i - mean))*p[i];
    }
}

double Histogram::thirdMoment(){
    double result = 0;
    for(int i = 0; i < 256; i++){
//        std::cout << "(i - mean) = " << (i - mean)*(i - mean)*(i - mean) << std::endl;
        result += ((i - mean)*(i - mean)*(i - mean))*p[i];
    }
    return result;
}

double Histogram::uniformity(){
    double result = 0;
    for(int i = 0; i < 256; i++){
        result += p[i]*p[i];
    }
    return result;
}

double Histogram::entropy(){
    double result = 0;
    for(int i = 0; i < 256; i++){
//        std::cout << "p[" << i << "] = " << p[i]  << "\tlog" << log(p[i]) << std::endl;
        if(p[i] != 0.0) result += p[i]*(log(p[i]));
    }
    return -result/log(2);
}

void Histogram::calculate(Data *_data){
    int w = _data->getWidth(), h = _data->getHeight();

    double pSum[256];
    for (int i = 0; i < 256; i++)
        pSum[i] = 0.0;

    int size = 4;
    for(int j = 0; j < h; j++){
        for(int i = j * size * w; i < (j + 1) * size * w; i += size){
            pSum[(int)_data->getData(i)] += 1.0/(w*h);
        }
    }

    for(int i = 0; i < 256; i++){
        p[i] = pSum[i];
    }
}


double Histogram::normalize(double x0, double xn, double y0, double yn, double x){
    double i = ((x - x0) * (yn - y0)) / (xn - x0) + y0;
    return i;
}
